﻿using System.Collections.Generic;
using Spring.Context.Support;
using Spring.Context;
using Spring.Objects.Factory.Config;
using Spring.Objects.Factory.Support;

namespace FluentSpring
{
    public class FluentConfigurator
    {

        private GenericApplicationContext applicationContext;

        private Queue<ConfigContext> pendingConfigs; 

        public FluentConfigurator()
        {
            applicationContext = new GenericApplicationContext();
            pendingConfigs = new Queue<ConfigContext>();
        }

        /// <summary>
        /// This is mostly for testing purposes.
        /// </summary>
        /// <param name="applicationContext"></param>
        /// <param name="configQueue"></param>
        public FluentConfigurator(GenericApplicationContext applicationContext, Queue<ConfigContext> configQueue)
        {
            this.applicationContext = applicationContext;
            pendingConfigs = configQueue;
        }

        public RootStep Register<T>()
        {
            ConfigContext context = new ConfigContext();
            context.RegisteredType = typeof(T);

            pendingConfigs.Enqueue(context);
            return new RootStep(context);
        }

        public IApplicationContext ToSpring()
        {
            while (pendingConfigs.Count > 0)
            {
                ConfigContext ctx = pendingConfigs.Dequeue();
                IObjectDefinition objectDefinition = BuildObjectDefinition(ctx);
                applicationContext.RegisterObjectDefinition(ctx.Identifier, objectDefinition);
            }

            return applicationContext;
        }

        protected virtual void ValidateConfigContext(ConfigContext configContext)
        {
            if (configContext == null) throw new FluentSpringException("Configuration context is null");
            if (configContext.RegisteredType == null) throw new FluentSpringException("Registered Type is null");
        }

        private  IObjectDefinition BuildObjectDefinition(ConfigContext configContext)
        {
            ValidateConfigContext(configContext);

            IObjectDefinitionFactory objectDefinitionFactory = new DefaultObjectDefinitionFactory();
            ObjectDefinitionBuilder builder =
                ObjectDefinitionBuilder.RootObjectDefinition(objectDefinitionFactory, configContext.RegisteredType);

            foreach (BuilderAction action in configContext.BuilderActionList)
            { action(builder); }

            return builder.ObjectDefinition;
        }


        
    }
}
